package netGaming;

import java.io.*;
import java.net.*;

import gameBasicElements.*;
import gameEngine.GameInfo;
import gameEngine.GameStatus;
import player.*;

/**
 * @author Wojciech Łopata
 *
 */

public class NetPlayer implements Player
{
	private ServerSocket server;
	private Socket client;
	
	private volatile GameStatus status;
	private ServerDataSender dataSender;
	private volatile Position nextMove;
	
	public NetPlayer(int port) throws IOException
	{
		status = GameStatus.NOT_STARTED;
		server = new ServerSocket(port);
	}
	
	@Override
	public synchronized void startGame(GameInfo gameInfo, PlayerColor thisPlayerColor) throws PlayerNotRespondingException
	{
		if(!status.equals(GameStatus.NOT_STARTED)) throw new IllegalStateException("Game already started");
		status = GameStatus.OK;
		try
		{
			client = server.accept();
			new ServerListener(this, client.getInputStream()).start();
			dataSender = new ServerDataSender(client.getOutputStream(), gameInfo);
			dataSender.sendGameBeginInfo(thisPlayerColor);
		} catch (IOException e)
		{
			try { client.close(); } catch (IOException e1) {}
			changeStatus(GameStatus.CANNOT_ESTABILISH_CONNECTION);
			throw new PlayerNotRespondingException("Connection with client could not be estabilished: " + e);
		}
		
	}
	
	@Override
	public synchronized Position getMove() throws PlayerNotRespondingException
	{
		try
		{
			this.dataSender.sendMoveRequest();
		} catch (IOException e)
		{
			changeStatus(GameStatus.CONNECTION_LOST);
			throw new PlayerNotRespondingException("Could not send move request to client");
		}
		
		while(nextMove == null && status.equals(GameStatus.OK))
		{
			try
			{
				wait();
			} catch (InterruptedException e)
			{
				throw new PlayerNotRespondingException("Thread was interrupted while waiting for player move. Maybe turn-time limit excedeed?");
			}
		}
		if(nextMove.getX() == -1) nextMove = null;
		if(! status.equals(GameStatus.OK))
		{
			throw new PlayerNotRespondingException("Problem occured: " + status);
		}
		Position move = nextMove;
		nextMove = null;
		notifyAll();
		return move;
	}
	
	@Override
	public void nextTurn() throws PlayerNotRespondingException
	{
		try
		{
			dataSender.sendGameStatus();
		} catch (IOException e1)
		{
			changeStatus(GameStatus.CONNECTION_LOST);
			throw new PlayerNotRespondingException("Could not send data to player " + e1);
		}
	}
	
	@Override
	public synchronized void endGame(ScoreBoard finalScores) throws PlayerNotRespondingException
	{
		status = GameStatus.SUCCESSFULLY_ENDED;
		try
		{
			dataSender.informAboutEndOfGame(finalScores);
		} catch (IOException e)
		{
			changeStatus(GameStatus.CONNECTION_LOST);
			throw new PlayerNotRespondingException("Unable to inform player about end of game. He lost?");
		}
		try
		{
			server.close();
			client.close();
		}
		catch (Exception e) {}
	}
	
	public GameStatus getStatus()
	{
		return status;
	}
	
	protected ServerDataSender getDataSender()
	{
		return dataSender;
	}

	protected boolean StillInGame()
	{
		return status.equals(GameStatus.OK) || status.equals(GameStatus.NOT_STARTED);
	}
	
	protected synchronized void setMove(Position move)
	{
		this.nextMove = move;
		notifyAll();
	}
	
	protected synchronized void changeStatus(GameStatus newStatus)
	{
		status = newStatus;
	}
}
